#pragma once

#include <gflags/gflags.h>
#include <thread>
#include <cctype>
#include<brpc/server.h>
#include<butil/logging.h>

#include "utils.hpp"// 基础工具接口
#include "mysql_chat_session.hpp"// mysql数据管理客户端封装
#include "mysql_friend_apply.hpp"// mysql数据管理客户端封装
#include "mysql_friend_relation.hpp"// mysql数据管理客户端封装
#include "mysql_session_member.hpp"// mysql数据管理客户端封装

#include "data_es.hpp"//es数据管理客户端封装

#include "channel.hpp"  // 信道管理模块封装
#include "etcd.hpp"    // 服务注册模块封装  

#include "base.pb.h"// protobuf框架代码
#include "user.pb.h"
#include "friend.pb.h"
#include "message.pb.h"//这个的作用是为了获得历史的最后一条信息，制作UI界面的时候需要用到



// _user_service_name,_message_service_name,_mm_channels,
//                 _mysql_client,_es_client);
namespace zzy_mims
{
     class FriendServiceImpl:public FriendService
    {

    public:
        FriendServiceImpl(const std::string &user_service_name,
            const std::string &message_service_name,
            const ServChanManager::ptr &channels,
            const std::shared_ptr<odb::core::database> &mysql_client,
            const std::shared_ptr<elasticlient::Client> &es_client):
            _user_service_name(user_service_name),
            _message_service_name(message_service_name),
            _mm_channels(channels),
            _mysql_session_member_table(std::make_shared<SessionMemberTable>(mysql_client)),
            _mysql_friend_apply_table(std::make_shared<FriendApplyTable>(mysql_client)),
            _mysql_friend_relation_table(std::make_shared<FriendRelationTable>(mysql_client)),
            _mysql_chat_session_table(std::make_shared<ChatSessionTable>(mysql_client)),
            _es_user(std::make_shared<ESUser>(es_client))
            {
                _es_user->CreateIndex();
            };
        ~FriendServiceImpl(){};
        virtual void GetFriendList(google::protobuf::RpcController* controller,
            const ::zzy_mims::GetFriendListReq* request, 
            ::zzy_mims::GetFriendListRsp* response, 
            ::google::protobuf::Closure* done)
        {    
            //取出数据，检查数据，插入数据，填写回应
            brpc::ClosureGuard rpc_guard(done);//和RAII思想类似，在局部域结束后自动调用done->Run();
            response->set_request_id(request->request_id());
            auto err_handler = [this,response](const std::string& rid,const std::string& errmsg)
            {
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };
            //1.提取请求关键要素
            std::string uid = request->user_id();

            //2.从数据库查找好友id
            std::vector<std::string> uids =  _mysql_friend_relation_table->friends(uid);
            //3.根据uid查到用户信息组织回应
            std::unordered_map<std::string,UserInfo> uid_info_list;
            for(auto id:uids)
            uid_info_list.emplace(id,UserInfo());
            bool ret = _GetUserInfo(request->request_id(),uid_info_list);
            if(!ret)
            {
                LOG_ERROR("批量获取用户信息失败{}\n",request->request_id());
                err_handler(request->request_id(),"批量获取用户信息失败");
                return;
            }
            response->set_success(true);
            for(auto &uid_info:uid_info_list)
            response->add_friend_list()->CopyFrom(uid_info.second);
        
        }
        virtual void FriendRemove(google::protobuf::RpcController* controller,
            const ::zzy_mims::FriendRemoveReq* request, 
            ::zzy_mims::FriendRemoveRsp* response, 
            ::google::protobuf::Closure* done)
        {    
            //取出数据，检查数据，插入数据，填写回应
            brpc::ClosureGuard rpc_guard(done);//和RAII思想类似，在局部域结束后自动调用done->Run();
            response->set_request_id(request->request_id());
            auto err_handler = [this,response](const std::string& rid,const std::string& errmsg)
            {
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };
            //1.提取请求关键要素 
            std::string uid1 = request->user_id();
            std::string uid2 = request->peer_id();
            //2.从好友关系，会话，会话成员表的数据库中删除两人的好友关系和两人的单聊会话
            bool ret = _mysql_friend_relation_table->remove(uid1,uid2);
            if(!ret)
            {
                LOG_ERROR("删除好友关系失败{}:{}-{}\n",request->request_id(),uid1,uid2);
                err_handler(request->request_id(),"删除好友关系失败");
                return;
            }
            ret = _mysql_chat_session_table->remove(uid1,uid2);//这个同时会把会话成员表的相关会话成员删除
            if(!ret)
            {
                LOG_ERROR("删除单聊会话失败{}:{}-{}\n",request->request_id(),uid1,uid2);
                err_handler(request->request_id(),"删除单聊会话失败");
                return;
            }
            //3.组织回应
            response->set_success(true);
        
        }
        //这个只是申请为好友
        virtual void FriendAdd(google::protobuf::RpcController* controller,
            const ::zzy_mims::FriendAddReq* request, 
            ::zzy_mims::FriendAddRsp* response, 
            ::google::protobuf::Closure* done)
        {    
            //取出数据，检查数据，插入数据，填写回应
            brpc::ClosureGuard rpc_guard(done);//和RAII思想类似，在局部域结束后自动调用done->Run();
            response->set_request_id(request->request_id());
            auto err_handler = [this,response](const std::string& rid,const std::string& errmsg)
            {
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };
            //1.提取请求关键要素
            std::string sender_id = request->user_id();
            std::string accepter_id = request->respondent_id();
            //2.判断两人是否已经是好友了
            bool ret = _mysql_friend_relation_table->exist(sender_id,accepter_id);
            if(ret)
            {
                LOG_ERROR("好友申请失败，该用户已经是好友了{}:{}-{}\n",request->request_id(),sender_id,accepter_id);
                err_handler(request->request_id(),"好友申请失败，该用户已经是好友了");
                return;
            }
            //3.判断申请者是否曾经申请过，避免形成骚扰
            ret = _mysql_friend_apply_table->exist(sender_id,accepter_id);
            if(ret)
            {
                LOG_ERROR("申请已经发送，请避免多次操作{}:{}-{}\n",request->request_id(),sender_id,accepter_id);
                err_handler(request->request_id(),"申请已经发送，请避免多次操作");
                return;
            }
            //4.发送申请
            std::string ev_id = uuid();
            FriendApply fa(ev_id,sender_id,accepter_id);
            ret = _mysql_friend_apply_table->insert(fa);
            //5.组织回应
            response->set_success(true);
            response->set_notify_event_id(ev_id);
        
        }
        //处理好友申请
        virtual void FriendAddProcess(google::protobuf::RpcController* controller,
            const ::zzy_mims::FriendAddProcessReq* request, 
            ::zzy_mims::FriendAddProcessRsp* response, 
            ::google::protobuf::Closure* done)
        {    
            //取出数据，检查数据，插入数据，填写回应
            brpc::ClosureGuard rpc_guard(done);//和RAII思想类似，在局部域结束后自动调用done->Run();
            response->set_request_id(request->request_id());
            auto err_handler = [this,response](const std::string& rid,const std::string& errmsg)
            {
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };
            //1.提取请求关键要素
            std::string sender_id = request->apply_user_id();
            std::string accepter_id = request->user_id();
            bool isgree = request->agree();
            //2.判断是否真的有此申请
            bool ret = _mysql_friend_apply_table->exist(sender_id,accepter_id);
            if(!ret)
            {
                LOG_ERROR("此前两人没有申请过好友{}:{}-{}\n",request->request_id(),sender_id,accepter_id);
                err_handler(request->request_id(),"此前两人没有申请过好友");
                return;
            }
            //3.有申请就删除并处理这个申请
            ret = _mysql_friend_apply_table->remove(sender_id,accepter_id);
            if(!ret)
            {
                LOG_ERROR("删除好友申请事件失败{}:{}-{}\n",request->request_id(),sender_id,accepter_id);
                err_handler(request->request_id(),"删除好友申请事件失败");
                return;
            }
            //4.根据是否同意好友申请，处理这个申请
            std::string add_sid;
            if(isgree)
            {
                //同意的话就增加好友关系，单聊会话，单聊会话成员
                ret = _mysql_friend_relation_table->insert(sender_id,accepter_id);
                if(!ret)
                {
                    LOG_ERROR("增加好友关系失败{}:{}-{}\n",request->request_id(),sender_id,accepter_id);
                    err_handler(request->request_id(),"增加好友关系失败");
                    return;
                }
                add_sid = uuid();
                ChatSession cs(add_sid,"",ChatSessionType::SINGLE);
                ret = _mysql_chat_session_table->insert(cs);
                if(!ret)
                {
                    LOG_ERROR("增加单聊会话失败{}:{}-{}\n",request->request_id(),sender_id,accepter_id);
                    err_handler(request->request_id(),"增加单聊会话失败");
                    return;
                }
                SessionMember sm1(sender_id,add_sid);
                SessionMember sm2(accepter_id,add_sid);
                std::vector<SessionMember> sm_list ={sm1,sm2};
                ret = _mysql_session_member_table->insert(sm_list);
                if(!ret)
                {
                    LOG_ERROR("增加单聊会话成员失败{}:{}-{}\n",request->request_id(),sender_id,accepter_id);
                    err_handler(request->request_id(),"增加单聊会话成员失败");
                    return;
                }
            }
            response->set_success(true);
            response->set_new_session_id(add_sid);
        }
        virtual void FriendSearch(google::protobuf::RpcController* controller,
            const ::zzy_mims::FriendSearchReq* request, 
            ::zzy_mims::FriendSearchRsp* response, 
            ::google::protobuf::Closure* done)
        {    
            //取出数据，检查数据，插入数据，填写回应
            brpc::ClosureGuard rpc_guard(done);//和RAII思想类似，在局部域结束后自动调用done->Run();
            response->set_request_id(request->request_id());
            auto err_handler = [this,response](const std::string& rid,const std::string& errmsg)
            {
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };
            //1.提取请求关键要素
            std::string uid = request->user_id();
            std::string skey = request->search_key();
            //2.获取查询用户的好友列表，避免申请好友查询时查到已经为好友的用户
            std::vector<std::string> friends = _mysql_friend_relation_table->friends(uid);
            friends.emplace_back(uid);//当然也不能查询到自己
            //3.从es中利用关键字查询用户
            std::vector<User> users = _es_user->Search(skey,friends);
            //4.获取用户信息
            std::unordered_map<std::string,UserInfo> uid_info_list;
            for(auto& user:users)
            uid_info_list.emplace(user.user_id(),UserInfo());
            bool ret = _GetUserInfo(request->request_id(),uid_info_list);
            if(!ret)
            {
                LOG_ERROR("批量获取用户信息失败{}\n",request->request_id());
                err_handler(request->request_id(),"批量获取用户信息失败");
                return;
            }
            //5.组织回应
            response->set_success(true);
            for(auto &uid_info:uid_info_list)
            response->add_user_info()->CopyFrom(uid_info.second);
        
        }
        //根据一个用户id获取与他相关的会话信息(包括最后发的一条消息)，便于登录后浏览历史发送信息
        virtual void GetChatSessionList(google::protobuf::RpcController* controller,
            const ::zzy_mims::GetChatSessionListReq* request, 
            ::zzy_mims::GetChatSessionListRsp* response, 
            ::google::protobuf::Closure* done)
        {    
            //取出数据，检查数据，插入数据，填写回应
            brpc::ClosureGuard rpc_guard(done);//和RAII思想类似，在局部域结束后自动调用done->Run();
            response->set_request_id(request->request_id());
            auto err_handler = [this,response](const std::string& rid,const std::string& errmsg)
            {
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };
            //1.提取请求关键要素
            std::string uid = request->user_id();
            //2.根据用户id查询单聊会话,并根据查询到的单聊会话得到朋友id，从而得到用户信息，从而设置单聊会话的信息
            std::vector<SingleChatSession> scs_list = _mysql_chat_session_table->singleChatSession(uid);
            std::unordered_map<std::string,UserInfo> uid_info_list;
            for(auto& scs:scs_list)
            uid_info_list.emplace(scs.friend_id,UserInfo());
            bool ret = _GetUserInfo(request->request_id(),uid_info_list);
            if(!ret)
            {
                LOG_ERROR("批量获取用户信息失败{}\n",request->request_id());
                err_handler(request->request_id(),"批量获取用户信息失败");
                return;
            }
            //3.根据用户id查询群聊会话
            std::vector<GroupChatSession> gcs_list = _mysql_chat_session_table->groupChatSession(uid);
            //4.组织回应
            for(auto& scs:scs_list)
            {
                auto chat_session_info = response->add_chat_session_info_list();
                chat_session_info->set_single_chat_friend_id(scs.friend_id);
                chat_session_info->set_chat_session_id(scs.sid);
                chat_session_info->set_chat_session_name(uid_info_list[scs.friend_id].nickname());
                chat_session_info->set_avatar(uid_info_list[scs.friend_id].avatar());
                MessageInfo msg;
                ret = _GetRecentOneMsg(request->user_id(),scs.sid,msg);
                if(!ret) continue;//获取消息错误或者新会话没有消息
                chat_session_info->mutable_prev_message()->CopyFrom(msg);
            }
            for(auto& gcss:gcs_list)
            {
                auto chat_session_info = response->add_chat_session_info_list();
                chat_session_info->set_chat_session_id(gcss.sid);
                chat_session_info->set_chat_session_name(gcss.sname);
                MessageInfo msg;
                ret = _GetRecentOneMsg(request->user_id(),gcss.sid,msg);
                if(!ret) continue;//获取消息错误或者新会话没有消息
                chat_session_info->mutable_prev_message()->CopyFrom(msg);
            }
            response->set_success(true);
        
        }
        //创建群聊会话
        virtual void ChatSessionCreate(google::protobuf::RpcController* controller,
            const ::zzy_mims::ChatSessionCreateReq* request, 
            ::zzy_mims::ChatSessionCreateRsp* response, 
            ::google::protobuf::Closure* done)
        {    
            //取出数据，检查数据，插入数据，填写回应
            brpc::ClosureGuard rpc_guard(done);//和RAII思想类似，在局部域结束后自动调用done->Run();
            response->set_request_id(request->request_id());
            auto err_handler = [this,response](const std::string& rid,const std::string& errmsg)
            {
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };
            //1.提取请求关键要素
            std::string uid = request->user_id();
            std::string sname =  request->chat_session_name();
            //2.在会话，会话成员数据库增添
            std::string sid = uuid();
            ChatSession cs(sid,sname,ChatSessionType::GROUP);
            bool ret = _mysql_chat_session_table->insert(cs);
            if(!ret)
            {
                LOG_ERROR("增加群聊会话失败{}-{}\n",request->request_id(),sname);
                err_handler(request->request_id(),"增加群聊会话失败");
                return;
            }
            std::vector<SessionMember> sm_list;
            for(int i =0;i<request->member_id_list_size();i++)
            {
                SessionMember sm(request->member_id_list(i),sid);
                sm_list.emplace_back(sm);
            }
            ret = _mysql_session_member_table->insert(sm_list);
            if(!ret)
            {
                LOG_ERROR("增加群聊会话成员失败{}-{}\n",request->request_id(),sname);
                err_handler(request->request_id(),"增加群聊会话成员失败");
                return;
            }
            //组织回应
            response->set_success(true);
            response->mutable_chat_session_info()->set_chat_session_id(sid);
            response->mutable_chat_session_info()->set_chat_session_name(sname);
        
        }
        virtual void GetChatSessionMember(google::protobuf::RpcController* controller,
            const ::zzy_mims::GetChatSessionMemberReq* request, 
            ::zzy_mims::GetChatSessionMemberRsp* response, 
            ::google::protobuf::Closure* done)
        {    
            //取出数据，检查数据，插入数据，填写回应
            brpc::ClosureGuard rpc_guard(done);//和RAII思想类似，在局部域结束后自动调用done->Run();
            response->set_request_id(request->request_id());
            auto err_handler = [this,response](const std::string& rid,const std::string& errmsg)
            {
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };
            //1.提取请求关键要素
            std::string sid = request->chat_session_id();
            //2.从数据库中获得请求会话的所有成员id,并使用用户子服务根据用户id查询用户信息
            auto uid_list = _mysql_session_member_table->members(sid);
            std::unordered_map<std::string,UserInfo> uid_info_list;
            for(auto& uid:uid_list)
            uid_info_list[uid] =UserInfo();
            bool ret = _GetUserInfo(request->request_id(),uid_info_list);
            if(!ret)
            {
                LOG_ERROR("批量获取用户信息失败{}\n",request->request_id());
                err_handler(request->request_id(),"批量获取用户信息失败");
                return;
            }
            //3.组织回应
            response->set_success(true);
            for(auto &uid_info:uid_info_list)
             response->add_member_info_list()->CopyFrom(uid_info.second);
            
        }
        virtual void GetPendingFriendEventList(google::protobuf::RpcController* controller,
            const ::zzy_mims::GetPendingFriendEventListReq* request, 
            ::zzy_mims::GetPendingFriendEventListRsp* response, 
            ::google::protobuf::Closure* done)
        {    
            //取出数据，检查数据，插入数据，填写回应
            brpc::ClosureGuard rpc_guard(done);//和RAII思想类似，在局部域结束后自动调用done->Run();
            response->set_request_id(request->request_id());
            auto err_handler = [this,response](const std::string& rid,const std::string& errmsg)
            {
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };
            //1.提取请求关键要素
            std::string uid = request->user_id();
            //2.从数据库中获得请求用户的好友申请的发送者id,并使用用户子服务根据用户id查询用户信息
            auto uid_list = _mysql_friend_apply_table->applyUsers(uid);
            std::unordered_map<std::string,UserInfo> uid_info_list;
            for(auto& uid:uid_list)
            uid_info_list[uid] =UserInfo();
            bool ret = _GetUserInfo(request->request_id(),uid_info_list);
            if(!ret)
            {
                LOG_ERROR("批量获取用户信息失败{}\n",request->request_id());
                err_handler(request->request_id(),"批量获取用户信息失败");
                return;
            }
            //3.组织回应
            response->set_success(true);
            for(auto &uid_info:uid_info_list)
            response->add_event()->mutable_sender()->CopyFrom(uid_info.second);
        
        }
    private:
        bool _GetUserInfo(const std::string& rid,std::unordered_map<std::string,UserInfo>& uid_info_list)
        {
            auto channel = _mm_channels->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("获取用户子服务信道失败:{}\n", rid);
                return false;
            }
            //1.获取rpc服务调用句柄
            ::zzy_mims::UserService_Stub stub(channel.get());
            //2.填写请求
            zzy_mims::GetMultiUserInfoReq  request;
            zzy_mims::GetMultiUserInfoRsp response;
            
            request.set_request_id(rid);
            for(auto& uid_info:uid_info_list)
            request.add_users_id(uid_info.first);
   
            //3.调用服务
            brpc::Controller cntl;
            stub.GetMultiUserInfo(&cntl,&request,&response,nullptr);//同步调用
            //4.验证应答是否符合预期
            if (cntl.Failed() == true) {
                LOG_ERROR("用户子服务调用失败:{}-{}\n", rid, cntl.ErrorText());
                return false;
            }
            if ( response.success() == false) {
                LOG_ERROR("批量获取用户信息失败:{}-{}\n", rid, response.errmsg());
                return false;
            }
            for(auto& res_uid_info:response.users_info())
            uid_info_list[res_uid_info.first] = res_uid_info.second;
            return true;
        }
        bool _GetRecentOneMsg(const std::string& rid,const std::string& sid,MessageInfo& msg)
        {
            auto channel = _mm_channels->choose(_message_service_name);
            if(!channel)
            {
                LOG_ERROR("获取消息子服务信道失败:{}\n", rid);
                return false;
            }
            //1.获取rpc服务调用句柄
            ::zzy_mims::MsgStorageService_Stub stub(channel.get());
            //2.填写请求
            zzy_mims::GetRecentMsgReq  request;
            zzy_mims::GetRecentMsgRsp response;
            
            request.set_request_id(rid);
            request.set_chat_session_id(sid);
            request.set_msg_count(1);
   
            //3.调用服务
            brpc::Controller cntl;
            stub.GetRecentMsg(&cntl,&request,&response,nullptr);//同步调用
            //4.验证应答是否符合预期
            if (cntl.Failed() == true) {
                LOG_ERROR("消息子服务调用失败:{}-{}\n", rid, cntl.ErrorText());
                return false;
            }
            if (response.success() == false) {
                LOG_ERROR("获取最近1条消息信息失败:{}-{}\n", rid, response.errmsg());
                return false;
            }
            if(response.msg_list_size()>0)
            {
                msg.CopyFrom(response.msg_list(0));
                return true;
            }
            return false;
        }
    private:
        //mysql库中聊天会话成员表管理句柄
        SessionMemberTable::ptr _mysql_session_member_table;
        FriendApplyTable::ptr _mysql_friend_apply_table;
        FriendRelationTable::ptr _mysql_friend_relation_table;
        ChatSessionTable::ptr _mysql_chat_session_table;
        ESUser::ptr _es_user;

        //服务操作句柄
        ServChanManager::ptr _mm_channels;
        std::string _user_service_name;
        std::string _message_service_name;

    };
    class FriendServer
    {
    public:
        using ptr = std::shared_ptr<FriendServer>;
        FriendServer(const Discovery::ptr& service_discoverer,const std::shared_ptr<brpc::Server>& rpc_server)
        :_service_discoverer(service_discoverer),_rpc_server(rpc_server){};
        ~FriendServer(){};
        void start()
        {
            _rpc_server->RunUntilAskedToQuit();
        }
    private:
        Discovery::ptr _service_discoverer;
        std::shared_ptr<brpc::Server> _rpc_server;
    };
    class FriendServerBuilder
    {
    public:
    void make_es_object(const std::vector<std::string> host_list)
        {
            _es_client=ESClientFactory::create(host_list);
        }
        void make_mysql_object
            (const std::string& user,
            const std::string& password,
            const std::string& db,
            const std::string& host,
            const std::string& charset,
            const int port,const int conn_max_pool)
        {
            _mysql_client = ODBFactory::create(user,password,db,host,charset,port,conn_max_pool);
        }
        void make_discover_object(const std::string& etcd_host,
        const std::string& base_service_name,const std::string& user_service_name,const std::string& message_service_name)
        {
            _user_service_name = user_service_name;
            _message_service_name = message_service_name;

            _mm_channels = std::make_shared<ServChanManager>();
            _mm_channels->Declared(_user_service_name);
            _mm_channels->Declared(_message_service_name);

            auto online = bind(&zzy_mims::ServChanManager::ServiceOnline,_mm_channels.get(),std::placeholders::_1,std::placeholders::_2);
            auto offline = bind(&zzy_mims::ServChanManager::ServiceOffline,_mm_channels.get(),std::placeholders::_1,std::placeholders::_2);
            _service_discoverer = std::make_shared<zzy_mims::Discovery>(etcd_host,base_service_name,online,offline);
        }

        void make_reg_object(const std::string& reg_host,
            const std::string& service_name,
            const std::string& access_host)
        {
            _reg_client = std::make_shared<Registery>(reg_host);
            _reg_client->Register(service_name,access_host);
        }

        void make_rpc_server(uint16_t port, int32_t timeout, uint8_t num_threads)
        {
            if(!_es_client)
            {
                LOG_ERROR("构造rpc服务时,还未初始化ES客户端\n");
                abort();
            }
            
            if(!_mysql_client)
            {
                LOG_ERROR("构造rpc服务时,还未初始化MYSQL客户端\n");
                abort();
            }
            if(!_mm_channels)
            {
                LOG_ERROR("未初始化信道管理模块\n");
                abort();
            }
            _rpc_server = std::make_shared<brpc::Server>();
            FriendServiceImpl* friend_service = new FriendServiceImpl(_user_service_name,_message_service_name,_mm_channels,
                _mysql_client,_es_client);
            int ret = _rpc_server->AddService(friend_service,brpc::ServiceOwnership::SERVER_OWNS_SERVICE);
            if(ret==-1)
            {
                LOG_ERROR("添加RPC服务失败!");
                abort();
            }
            brpc::ServerOptions options;
            options.idle_timeout_sec=timeout;
            options.num_threads = num_threads;
            ret = _rpc_server->Start(port,&options);
            if(ret==-1)
            {
                LOG_ERROR("friend_RPC服务器启动失败");
                abort();
            }
        }
        FriendServer::ptr build()
        {
            if(!_rpc_server)
            {
                LOG_ERROR("构造FriendServer时,还未初始化rpc客户端\n");
                abort();
            }
            if(!_service_discoverer)
            {
                LOG_ERROR("构造FriendServer时,还未初始化discover客户端\n");
                abort();
            }
            if(!_reg_client)
            {
                LOG_ERROR("构造FriendServer时,还未初始化registry客户端\n");
                abort();
            }
            FriendServer::ptr server = std::make_shared<FriendServer>(_service_discoverer,_rpc_server);
            return server;
        }

    private:
    //服务发现
        Registery::ptr _reg_client;
        std::string _user_service_name;
        std::string _message_service_name;

        ServChanManager::ptr _mm_channels;
        std::shared_ptr<brpc::Server> _rpc_server;
        Discovery::ptr _service_discoverer;

    //数据库存储
        std::shared_ptr<odb::core::database> _mysql_client;
        std::shared_ptr<elasticlient::Client> _es_client;

    };

}